﻿using System;
using System.Collections.Generic;
using System.Text;


using CodeMap    = System.Collections.Generic.Dictionary<int, int>;
using SessionMap = System.Collections.Generic.Dictionary<int, UsrLoginManager.UsrLoginCahce>;
using AccountMap = System.Collections.Generic.Dictionary<string, UsrLoginManager.UsrLoginCahce>;
using ValidCodeArray = System.Collections.Generic.Stack<int>;

/**
*@file       usrloginmanager.cs
*@brief      usr login manage
*
*@author     graywind
*@version    1.0.0.0
*@data       2012/03/02
*/

public class UsrLoginManager
{
    #region private class
    public class UsrLoginCahce
    {
        #region property
        //usr account
        private string m_usrName;
        /// <summary>
        /// usr account
        /// </summary>
        public string Usrname
        {
            get
            {
                return m_usrName;
            }
            private set
            {
                m_usrName = value;
            }
        }
        //identifier of network session
        private int m_sessionId;
        /// <summary>
        /// identifier of network session
        /// </summary>
        public int SessionId
        {
            get
            {
                return m_sessionId;
            }
            private set
            {
                m_sessionId = value;
            }
        }
        //login code
        private int m_loginCode;
        /// <summary>
        /// login code
        /// </summary>
        public int LoginCode
        {
            get
            {
                return m_loginCode;
            }
            private set
            {
                m_loginCode = value;
            }
        }
        #endregion

        #region constructor
        /// <summary>
        /// constructor
        /// </summary>
        /// <param name="usr_name"></param>
        /// <param name="session_id"></param>
        /// <param name="login_code"></param>
        public UsrLoginCahce(string usr_name, int session_id, int login_code)
        {
            m_usrName = usr_name;
            m_sessionId = session_id;
            m_loginCode = login_code;
        }
        #endregion
    }
    #endregion
    #region public constant
    //define invalid code value
    public const int INVALID_CODE = -1;
    #endregion

    #region private variable
    //account map
    private AccountMap m_mapAccount = new AccountMap();
    //session map
    private SessionMap m_mapSession = new SessionMap();
    //current used
    private CodeMap m_mapCode = new CodeMap();
    //code left
    private ValidCodeArray m_arrayValid = new ValidCodeArray();
    //maxium code value
    private Int32 m_maxCode = 0;
    //lock object
    private Object m_lockObj = new Object();
    #endregion

    #region private call
    /// <summary>
    /// get a valid code
    /// </summary>
    /// <returns></returns>
    private int GetValidCode()
    {
        if (m_arrayValid.Count > 0)
            return m_arrayValid.Pop();
        else if (m_maxCode < Int32.MaxValue)
        {
            return m_maxCode++;
        }

        return INVALID_CODE;
    }
    #endregion

    #region constructor
    /// <summary>
    /// constuctor
    /// </summary>
    /// <param name="max_code"></param>
    public UsrLoginManager(int max_code)
    {
        for (m_maxCode = 0; m_maxCode < max_code; ++m_maxCode)
        {
            m_arrayValid.Push(m_maxCode);
        }
    }
    #endregion

    #region external call
    /// <summary>
    /// add a account
    /// </summary>
    /// <param name="usr_name"></param>
    /// <param name="session_id"></param>
    /// <returns></returns>
    public bool Add(string usr_name, int session_id, out int login_code)
    {
        login_code = INVALID_CODE;
        lock (m_lockObj)
        {
            if (!m_mapAccount.ContainsKey(usr_name))
            {
                login_code = GetValidCode();
                if (login_code != INVALID_CODE)
                {
                    UsrLoginCahce ulc = new UsrLoginCahce(usr_name, session_id, login_code);
                    m_mapAccount.Add(usr_name, ulc);
                    m_mapCode.Add(login_code, session_id);
                    m_mapSession.Add(session_id, ulc);
                }

                return true;
            }
        }

        return false;
    }

    /// <summary>
    /// get login code
    /// </summary>
    /// <param name="session_id"></param>
    /// <returns></returns>
    public int GetLoginCode(int session_id)
    {
        lock (m_lockObj)
        {
            UsrLoginCahce ulc;
            if (m_mapSession.TryGetValue(session_id, out ulc))
                return ulc.LoginCode;
        }

        return INVALID_CODE;
    }

    /// <summary>
    /// get login code
    /// </summary>
    /// <param name="usr_name"></param>
    /// <returns></returns>
    public int GetLoginCode(string usr_name)
    {
        lock (m_lockObj)
        {
            UsrLoginCahce ulc;
            if (m_mapAccount.TryGetValue(usr_name, out ulc))
                return ulc.LoginCode;
        }

        return INVALID_CODE;
    }

    /// <summary>
    /// get identifier of network session
    /// </summary>
    /// <param name="login_code"></param>
    /// <returns></returns>
    public int GetSessionId(int login_code)
    {
        lock (m_lockObj)
        {
            int session_id;
            if (m_mapCode.TryGetValue(login_code, out session_id))
                return session_id;
        }

        return NetLib.INVALID_SESSION;
    }

    /// <summary>
    /// recyle the code
    /// </summary>
    /// <param name="session_id"></param>
    public void Remove(int session_id)
    {
        lock (m_lockObj)
        {
            if (m_mapSession.ContainsKey(session_id))
            {
                UsrLoginCahce ulc = m_mapSession[session_id];
                m_mapCode.Remove(ulc.LoginCode);
                m_mapSession.Remove(ulc.SessionId);
                m_mapAccount.Remove(ulc.Usrname);

                m_arrayValid.Push(ulc.LoginCode);
            }
        }
    }
    #endregion
}